﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using System.Web;
using ARSys.Connector;

namespace ARSys.Entity
{
    [Table("CTM_People")]
    [ARForm("CTM:People")]
    public class People
    {
        #region Entity Key
        [AREntryId]
        [Column("Person_ID")]
        public string PeopleId { get; set; }
        #endregion

        #region CTM:People
        public People()
        {

        }

        [Column("Full_Name")]
        public string FullName { get; set; }

        [Column("Support_Staff")]
        [Description("0-Yes, 1-No")]
        [ARField(1000000025, ARSysProxy.C_AR_DATA_TYPE_INTEGER)]
        public int SupportStaff { get; set; }

        [Column("Profile_Status")]
        [Description("1-Enabled;5-Delete")]
        [ARField(7, ARSysProxy.C_AR_DATA_TYPE_INTEGER)]
        public int ProfileStatus { get; set; }

        [NotMapped]
        [ARField(1000005507, ARSysProxy.C_AR_DATA_TYPE_CHAR, AllowModify = false)]
        public string Password { get; set; }

        [NotMapped]
        [Description("2000-Office-Based Employee")]
        [ARField(1000000022, ARSysProxy.C_AR_DATA_TYPE_INTEGER, AllowModify = false)]
        public int ClientType { get; set; }

        [NotMapped]
        [Description("2-floating")]
        [ARField(109, ARSysProxy.C_AR_DATA_TYPE_INTEGER, AllowModify = false)]
        public int LicenseType { get; set; }
        #endregion

        #region Employee.csv
        private People(string[] data)
        {
            foreach (var prop in CsvMappedProperties)
            {
                object value = null;
                int index = Columns.IndexOf(prop.Name);
                string buffer = data[index];

                // we don't care the property type anyway and 
                //  consider all the data type as string
                value = buffer;

                prop.SetValue(this, value, null);
            }
        }

        public static People FromRawData(string rawData, dynamic extraData)
        {
            if (string.IsNullOrEmpty(rawData))
                throw new ArgumentNullException("rawData");

            if (extraData == null)
                throw new ArgumentNullException("extraData");

            var data = rawData.Replace("\",\"", "§").Trim('"').Split('§');
            if (data.Length != Columns.Count)
                throw new ArithmeticException(String.Format("The input data source [{0}] doesn't match the predefined data format [{1}]", data.Length, Columns.Count));

            var ppl = new People(data);

            //

            if (ppl.Status == "ON")
                ppl.ProfileStatus = 1;
            else
                ppl.ProfileStatus = 5;

            ppl.Password = extraData.Password;
            ppl.ClientType = extraData.ClientType;
            ppl.LicenseType = extraData.LicenseType;
            ppl.SupportStaff = extraData.SupportStaff;
            ppl.Company = extraData.Company;

            if (ppl.FirstName == "") ppl.FirstName = "(null)";
            if (ppl.LastName == "") ppl.LastName = "(null)";
            if (ppl.Telephone == "") ppl.Telephone = "(null)";
            //

            return ppl;
        }

        // Use this field as primary key
        [Key]
        [CsvMapped]
        [Column("Accounting_Number")]
        [ARField(240000042, ARSysProxy.C_AR_DATA_TYPE_CHAR, AllowModify = false)]
        public string EmployeeID { get; set; }

        [NotMapped]
        public string CSL { get; set; }

        [CsvMapped]
        [Column("Remedy_Login_ID")]
        [ARField(4, ARSysProxy.C_AR_DATA_TYPE_CHAR, AllowModify = false)]
        public string CIL { get; set; }

        [NotMapped]
        public string ADAccount { get; set; }

        [Comparable]
        [CsvMapped]
        [Column("ACD_Phone_Num")]
        [ARField(1000000047, ARSysProxy.C_AR_DATA_TYPE_CHAR)]
        public string UPI { get; set; }

        [Comparable]
        [CsvMapped]
        [Column("Nick_Name")]
        [ARField(1000000024, ARSysProxy.C_AR_DATA_TYPE_CHAR, MaxLength = 25)]
        public string Name { get; set; }

        [NotMapped]
        public string EName { get; set; }

        [Comparable]
        [CsvMapped]
        [Column("First_Name")]
        [ARField(1000000019, ARSysProxy.C_AR_DATA_TYPE_CHAR, MaxLength = 30)]
        public string FirstName { get; set; }

        [Comparable]
        [CsvMapped]
        [Column("Middle_Initial")]
        [ARField(1000000020, ARSysProxy.C_AR_DATA_TYPE_CHAR, MaxLength = 30)]
        public string MidName { get; set; }

        [Comparable]
        [CsvMapped]
        [Column("Last_Name")]
        [ARField(1000000018, ARSysProxy.C_AR_DATA_TYPE_CHAR, MaxLength = 30)]
        public string LastName { get; set; }

        [Comparable]
        [CsvMapped]
        [Column("Corporate_E_Mail")]
        [ARField(1000000049, ARSysProxy.C_AR_DATA_TYPE_CHAR, MaxLength = 128)]
        public string Email { get; set; }

        [NotMapped]
        public string MailStore { get; set; }

        [NotMapped]
        public string CILX500 { get; set; }

        [NotMapped]
        public string CompanyID { get; set; }

        [NotMapped]
        [ARField(1000000001, ARSysProxy.C_AR_DATA_TYPE_CHAR, MaxLength = 254, AllowModify = false)]
        public string Company { get; set; }

        [NotMapped]
        public string PlatformID { get; set; }

        [NotMapped]
        public string DeptID { get; set; }

        [CsvMapped]
        [NotMapped]
        [ARField(200000006, ARSysProxy.C_AR_DATA_TYPE_CHAR, MaxLength = 60, AllowModify = false)]
        public string Department { get; set; }

        [NotMapped]
        public string SubDeptID { get; set; }

        [NotMapped]
        public string CostCenterID { get; set; }

        [NotMapped]
        public string PositionCN { get; set; }

        [CsvMapped]
        [NotMapped]
        [ARField(1000000023, ARSysProxy.C_AR_DATA_TYPE_CHAR, MaxLength = 50, AllowModify = false)]
        public string Position { get; set; }

        [NotMapped]
        public string Category { get; set; }

        [NotMapped]
        public string ECategory { get; set; }

        [NotMapped]
        public string XType { get; set; }

        [NotMapped]
        public string ReportTo { get; set; }

        [CsvMapped]
        [NotMapped]
        public string Status { get; set; }

        [NotMapped]
        public string StartDate { get; set; }

        [NotMapped]
        public string EndDate { get; set; }

        [NotMapped]
        public string LeaveDate { get; set; }

        [CsvMapped]
        [NotMapped]
        [ARField(1000000056, ARSysProxy.C_AR_DATA_TYPE_CHAR, MaxLength = 50, AllowModify = false)]
        public string Telephone { get; set; }

        [NotMapped]
        public string OnNet { get; set; }

        [NotMapped]
        public string ULI { get; set; }

        [NotMapped]
        public string FAX { get; set; }

        [NotMapped]
        public string OrigLocation { get; set; }

        [CsvMapped]
        [NotMapped]
        [ARField(1000000059, ARSysProxy.C_AR_DATA_TYPE_CHAR, MaxLength = 50, AllowModify = false)]
        public string Mobile { get; set; }

        [NotMapped]
        public string ModifyTime { get; set; }

        [NotMapped]
        public string AccLocation { get; set; }

        [NotMapped]
        public string DeleteFlag { get; set; }

        [NotMapped]
        public string DeleteTIme { get; set; }

        [NotMapped]
        public string reportupi { get; set; }

        [NotMapped]
        public string EID { get; set; }

        [CsvMapped]
        [NotMapped]
        [ARField(1000000046, ARSysProxy.C_AR_DATA_TYPE_CHAR, MaxLength = 20, AllowModify = false)]
        public string ADdomain { get; set; }

        [NotMapped]
        public string WorkLocationEN { get; set; }

        [NotMapped]
        public string WorkLocationCN { get; set; }


        #region Employee.csv Columns & PropertyInfos
        private static readonly IEnumerable<PropertyInfo> CsvMappedProperties =
            typeof(People).GetProperties().Where(p => p.HasAttribute<CsvMappedAttribute>()).ToArray();

        // Do not modify the following list (name or order) unless the data format of Employee.csv changes
        private static readonly List<String> Columns = new string[] { 
            "EmployeeID",
            "CSL",
            "CIL",
            "ADAccount",
            "UPI",
            "Name",
            "EName",
            "FirstName",
            "MidName",
            "LastName",
            "Email",
            "MailStore",
            "CILX500",
            "CompanyID",
            "Company",
            "PlatformID",
            "DeptID",
            "Department",
            "SubDeptID",
            "CostCenterID",
            "PositionCN",
            "Position",
            "Category",
            "ECategory",
            "XType",
            "ReportTo",
            "Status",
            "StartDate",
            "EndDate",
            "LeaveDate",
            "Telephone",
            "OnNet",
            "ULI",
            "FAX",
            "OrigLocation",
            "Mobile",
            "ModifyTime",
            "AccLocation",
            "DeleteFlag",
            "DeleteTIme",
            "reportupi",
            "EID",
            "ADdomain",
            "WorkLocationEN",
            "WorkLocationCN",
                                                   }.ToList();
        #endregion

        private class CsvMappedAttribute : Attribute
        {

        }

        #endregion


        #region != Operator
        public static bool operator ==(People a, People b)
        {
            if (ReferenceEquals(a, b))
                return true;
            else if (ReferenceEquals(a, null) || ReferenceEquals(b, null))
                return false;
            else
                return ComparableProperties.All(p =>
                {
                    var va = p.GetValue(a, null);
                    var vb = p.GetValue(b, null);

                    //Wicresoft.Logger.Log.Debug("Comparable", "{3}:{2}, a={0}, b={1}, {4}", va, vb, p.Name, a.EmployeeID, object.Equals(va, vb));

                    if (string.IsNullOrEmpty(va as string) &&
                        string.IsNullOrEmpty(vb as string))
                        return true;
                    else
                        return object.Equals(va, vb);
                });
        }
        public static bool operator !=(People a, People b)
        {
            return !(a == b);
        }
        public override bool Equals(object obj)
        {
            if (obj is People)
            {
                return (obj as People) == this;
            }
            else
                return false;
        }
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
        private static readonly IEnumerable<PropertyInfo> ComparableProperties =
            typeof(People).GetProperties().Where(p => p.HasAttribute<ComparableAttribute>()).ToArray();
        #endregion
    }

    public class ComparableAttribute : Attribute
    {
    }

    public static class PropertyInfoExtension
    {
        public static bool HasAttribute<T>(this PropertyInfo source)
            where T : Attribute
        {
            return source.GetCustomAttributes(false).Any(p => p is T);
        }
    }
}